import { Project, Node } from "ts-morph";
import fs from "fs";
import path from "path";
import JSON5 from "json5";
import { fileURLToPath } from "url";

// 获取当前文件的路径
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// --- 从命令行参数获取目标目录 ---
const targetDir = process.argv[2];
if (!targetDir || !fs.existsSync(targetDir)) {
    console.error("错误：请提供一个有效的目标目录路径作为参数。");
    console.error("用法: node extract_functions.js <path_to_your_library_or_libraries>");
    process.exit(1);
}

// 创建一个新的 ts-morph 项目
const project = new Project();

// 定义需要忽略的文件夹名称
const IGNORED_SUBDIRECTORIES = [
    "example", "examples", "test", "__tests__", "docs", "documentation",
    "build", "perf", "scripts", "benchmark", "__benchmark__", "coverage",
    "config", "mocks", "fixtures",
];

// 定义存储函数的 JSON 结构
const functionsData = {
    totalFunctions: 0,
    functions: [],
};

// 支持的输入文件类型
const SUPPORTED_EXTENSIONS = [".js", ".cjs", ".mjs", ".ts", ".ets"];

// 保证函数体的内容符合标准的大括号封装格式
function ensureBraces(str) {
    const regex = /^\{[\s\S]*}$/;
    if (!regex.test(str)) {
        str = '{' + str + '}';
    }
    return str;
}

/**
 * 递归遍历文件夹中的所有文件
 * @param {string} dirPath - 文件夹路径
 * @param {string} libraryName - 库名称
 * @param {string} libraryVersion - 库版本
 */
function traverseDirectory(dirPath, libraryName, libraryVersion) {
    const items = fs.readdirSync(dirPath);
    for (const item of items) {
        const itemPath = path.join(dirPath, item);
        const stat = fs.statSync(itemPath);

        if (stat.isDirectory()) {
            if (IGNORED_SUBDIRECTORIES.includes(item)) {
                console.log(`忽略子文件夹: ${itemPath}`);
                continue;
            }
            traverseDirectory(itemPath, libraryName, libraryVersion);
        } else if (stat.isFile() && SUPPORTED_EXTENSIONS.includes(path.extname(item).toLowerCase())) {
            const fileName = itemPath.split(path.sep).at(-1);
            const isDotXxJs = /\.(?!.*\.).+\.js$/.test(fileName);
            if (isDotXxJs) continue;

            const specialIgnoredPatterns = [
                /\.d\.ts$/, /\.test\.ts$/, /\.min\.js$/, /\.prod\.js$/,
                /\.light\.js$/, /\.full\.js$/, /\.eslintrc\.js$/,
                /\.config\.js$/, /\.config\.ts$/, /\.conf\.js$/
            ];
            if (specialIgnoredPatterns.some(pattern => pattern.test(fileName))) continue;

            const ignoreFileName = ["Gruntfile.js"];
            if (ignoreFileName.includes(fileName)) continue;

            processFile(itemPath, libraryName, libraryVersion);
        }
    }
}

/**
 * 处理单个文件，提取函数信息
 * @param {string} filePath - 文件路径
 * @param {string} libraryName - 库名称
 * @param {string} libraryVersion - 库版本
 */
function processFile(filePath, libraryName, libraryVersion) {
    const relativePath = path.relative(targetDir, filePath);
    let sourceFilePath = filePath;

    if (filePath.endsWith(".ets")) {
        const tempFilePath = filePath.replace(/\.ets$/, `.temp_${Date.now()}.ts`);
        if (!fs.existsSync(filePath)) {
            console.error(`文件不存在: ${filePath}`);
            return;
        }
        try {
            fs.copyFileSync(filePath, tempFilePath);
            sourceFilePath = tempFilePath;
        } catch (error) {
            console.error(`复制文件失败: ${filePath} -> ${tempFilePath}`, error);
            return;
        }
    }

    const sourceFile = project.addSourceFileAtPath(sourceFilePath);

    sourceFile.forEachDescendant(node => {
        // ... (这部分代码与你的原始代码完全相同，保持不变) ...
        if (Node.isFunctionDeclaration(node)) {
            const LineNumber = node.getEndLineNumber() - node.getStartLineNumber();
            let isNestedFunction = false;
            node.forEachDescendant((child, traversal) => {
                if (Node.isFunctionDeclaration(child)) {
                    console.log("发现嵌套函数，跳过外层");
                    isNestedFunction = true;
                    traversal.stop();
                }
            });
            if (LineNumber > 1000 || isNestedFunction) return;

            const functionName = node.getName() || "anonymous";
            const functionBody = node.getBody()?.getText() || "{}";
            addFunctionToData(functionName, functionBody, "function", libraryName, libraryVersion, relativePath);
        } else if (Node.isArrowFunction(node)) {
            const LineNumber = node.getEndLineNumber() - node.getStartLineNumber();
            if (LineNumber > 1000) return;
            const functionName = "anonymous";
            const functionBody = node.getBody().getText() || "{}";
            addFunctionToData(functionName, functionBody, "arrow function", libraryName, libraryVersion, relativePath);
        } else if (Node.isMethodDeclaration(node)) {
            const functionName = node.getName() || "anonymous";
            const functionBody = node.getBody()?.getText() || "{}";
            addFunctionToData(functionName, functionBody, "method", libraryName, libraryVersion, relativePath);
        } else if (Node.isFunctionExpression(node)) {
            const parentNode = node.getParent();
            if (Node.isParenthesizedExpression(parentNode)) {
                const rootNode = parentNode.getParent();
                if (Node.isCallExpression(rootNode)) return;
            }
            const LineNumber = node.getEndLineNumber() - node.getStartLineNumber();
            if (LineNumber > 1000) return;
            const functionName = "anonymous";
            const functionBody = node.getBody()?.getText() || "{}";
            addFunctionToData(functionName, functionBody, "function expression", libraryName, libraryVersion, relativePath);
        }
    });

    if (filePath.endsWith(".ets")) {
        try {
            fs.unlinkSync(sourceFilePath);
        } catch (error) {
            console.error(`删除临时文件失败: ${sourceFilePath}`, error);
        }
    }
}

/**
 * 将函数信息添加到 functionsData 中
 */
function addFunctionToData(name, body, type, library, version, relativePath) {
    body = ensureBraces(body);
    if (body === "{}") return;
    functionsData.functions.push({
        type, name, body, library, version,
        relativePath: relativePath.replace(/\\/g, "/"),
    });
}


/**
 * 处理单个库
 * @param {string} fallbackLibraryName - 备用库名称（通常是文件夹名）
 * @param {string} libraryPath - 库路径
 */
function processLibrary(fallbackLibraryName, libraryPath) {
    let libraryVersion = "unknown";
    // 默认使用传入的备用库名称（文件夹名）
    let finalLibraryName = fallbackLibraryName;

    const ohPackageJson5Path = path.join(libraryPath, "oh-package.json5");
    if (fs.existsSync(ohPackageJson5Path)) {
        try {
            const ohPackageJsonContent = fs.readFileSync(ohPackageJson5Path, "utf-8");
            const ohPackageJson = JSON5.parse(ohPackageJsonContent);

            // --- 关键修改点 ---
            // 优先使用 oh-package.json5 中的 name 属性
            if (ohPackageJson.name && typeof ohPackageJson.name === 'string' && ohPackageJson.name.trim() !== '') {
                finalLibraryName = ohPackageJson.name.trim();
            }
            // --------------------

            libraryVersion = ohPackageJson.version || "unknown";
        } catch (error) {
            console.error(`解析 oh-package.json5 文件失败: ${ohPackageJson5Path}`, error);
        }
    }

    console.log(`正在处理库: ${finalLibraryName} (版本: ${libraryVersion})`);
    // 使用最终确定的库名称进行遍历
    traverseDirectory(libraryPath, finalLibraryName, libraryVersion);
}

// --- 重构后的主函数 ---
function main() {
    console.log(`开始分析目录: ${targetDir}`);

    // 检查目标目录下是否包含 oh-package.json5
    const ohPackagePath = path.join(targetDir, 'oh-package.json5');

    if (fs.existsSync(ohPackagePath)) {
        // 情况 (2): 是一个完整的库目录
        console.log("检测到单个库目录，开始处理...");
        const libraryName = path.basename(targetDir);
        processLibrary(libraryName, targetDir);
    } else {
        // 情况 (1): 是多个库的根目录
        console.log("检测到多个库的根目录，开始遍历处理...");
        const libraries = fs.readdirSync(targetDir, { withFileTypes: true })
            .filter(dirent => dirent.isDirectory() && !dirent.name.startsWith("."))
            .map(dirent => dirent.name);

        if (libraries.length === 0) {
            console.log("在指定目录下未找到任何子文件夹。");
            return;
        }

        libraries.forEach(libraryName => {
            const libraryPath = path.join(targetDir, libraryName);
            if (libraryName.startsWith('@')) {
                const subLibraries = fs.readdirSync(libraryPath, { withFileTypes: true })
                    .filter(dirent => dirent.isDirectory() && !dirent.name.startsWith("."))
                    .map(dirent => dirent.name);
                subLibraries.forEach(subLibraryName => {
                    const subLibraryPath = path.join(libraryPath, subLibraryName);
                    processLibrary(subLibraryName, subLibraryPath);
                });
            } else {
                processLibrary(libraryName, libraryPath);
            }
        });
    }

    // 更新函数总数
    functionsData.totalFunctions = functionsData.functions.length;
    console.log(`总共提取了 ${functionsData.totalFunctions} 个函数。`);

    // 将函数数据写入固定的 JSON 文件
    const outputFilePath = path.join(__dirname, "extracted_functions.json");
    fs.writeFileSync(outputFilePath, JSON.stringify(functionsData, null, 2));
    console.log(`函数数据已成功保存到: ${outputFilePath}`);
}

// 运行主函数
main();
